﻿using System;
using System.Collections; 
using System.Collections.Generic;
using System.IO; 
using System.Text;

namespace Parseq.Core
{
    public class Combinator
    {
        public static BaseParser Always(object result)
        {
            return new DelegateParser(delegate(IReader reader, Location pos)
            {
                return new Result(result, pos);
            });
        }

        public static CharParser CharAny()
        {
            return new CharParser(); 
        }

        public static CharParser CharEquals(char c)
        {
            return new CharEquals(c); 
        }

        public static CharParser CharNotEquals(char c)
        {
            return new CharEquals(c, true); 
        }

        public static CharParser CharIn(params char[] chars)
        {
            return new CharIn(chars);
        }

        public static CharParser CharNotIn(params char[] chars)
        {
            return new CharIn(chars, true); 
        }

        public static CharParser CharBetween(char low, char high)
        {
            return new CharBetween(low, high);
        }

        public static CharParser CharNotBetween(char low, char high)
        {
            return new CharBetween(low, high);
        }

        public static CharParser CharOneOf(params CharParser[] parsers)
        {
            return new CharOneOf(parsers); 
        }

        public static CharParser CharIsDigit()
        {
            return CharBetween('0', '9');
        }
		
		public static CharParser CharIsLowerAlpha() {
			return CharBetween('a','z');
		}
		
		public static CharParser CharIsUpperAlpha() {
			return CharBetween('A','Z');
		}
		
		public static CharParser CharIsAlpha() {
			return CharOneOf(CharIsLowerAlpha(), CharIsUpperAlpha()); 
		}
		
		public static CharParser CharIsAlphaNumeric() {
			return CharOneOf(CharIsAlpha(), CharIsDigit()); 
		}

        public static CharParser CharFollowedBy(CharParser first, CharParser next)
        {
            return new CharFollowedBy(first, next); 
        }

        public static SequenceParser Sequence(params BaseParser[] parsers)
        {
            return MakeSequence(parsers);
        }

        public static SequenceParser MakeSequence(BaseParser[] parsers)
        {
            return new SequenceParser(parsers);
        }

        public static ChoiceParser Choice(params BaseParser[] parsers)
        {
            return MakeChoice(parsers);
        }

        public static ChoiceParser MakeChoice(BaseParser[] parsers)
        {
            return new ChoiceParser(parsers);
        }

        public static RepeatParser Repeat(BaseParser inner, long min, long max)
        {
            return new RepeatParser(inner, min, max, null, null);
        }

        public static RepeatParser Repeat(BaseParser inner, long min, long max, object defaultResult)
        {
            return new RepeatParser(inner, min, max, defaultResult, null);
        }

        public static RepeatParser Repeat(BaseParser inner, long min, long max, object defaultResult, BaseParser lazyInner)
        {
            return new RepeatParser(inner, min, max, defaultResult, lazyInner);
        }

        public static RepeatParser OneMany(BaseParser inner)
        {
            return Repeat(inner, 1, RepeatParser.INFINITE, null, null);
        }

        public static RepeatParser LazyOneMany(BaseParser inner, BaseParser lazyInner)
        {
            return Repeat(inner, 1, RepeatParser.INFINITE, null, lazyInner);
        }

        public static RepeatParser ZeroMany(BaseParser inner)
        {
            return Repeat(inner, 0, RepeatParser.INFINITE, new object[0], null);
        }

        public static RepeatParser LazyZeroMany(BaseParser inner, BaseParser lazyInner)
        {
            return Repeat(inner, 0, RepeatParser.INFINITE, new object[0], lazyInner);
        }

        public static ZeroOneParser ZeroOne(BaseParser inner, object defaultResult)
        {
            return new ZeroOneParser(inner, defaultResult); 
        }

        public static BaseParser Delimited(BaseParser inner, BaseParser delim)
        {
			return Combinator.Sequence(inner
				, Combinator.ZeroMany(Combinator.Sequence(delim, inner)
					.SetTransformArray(delegate(object[] delimInner) {
						return delimInner[1]; 
						}))).SetTransformArray(delegate(object[] headTail) {
                            return BaseParser.ObjectArrayJoin(headTail); 
			});
        }
		
        public static BaseParser Chars(string s)
        {
            return Chars(s.ToCharArray());
        }

        public static BaseParser Chars(char[] s)
        {
            BaseParser[] chars = new BaseParser[s.Length];
            for (int i = 0; i < s.Length; ++i)
            {
                chars[i] = CharEquals(s[i]);
            }
            return Combinator.MakeSequence(chars);
        }

        public static BaseParser MapCharsTo(string s, object o)
        {
            return ((BaseParser)Chars(s)).SetTransformArray(delegate(object[] chars) { return o; }); 
        }
		
    }
}
